package davion.study.summercloud.controller;

import davion.study.summercloud.model.FileStore;
import davion.study.summercloud.model.MyFile;
import davion.study.summercloud.model.User;
import davion.study.summercloud.service.FileFolderService;
import davion.study.summercloud.service.FileStoreService;
import davion.study.summercloud.service.MyFileService;
import davion.study.summercloud.util.FtpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @author: Davion
 * @date: 2020/6/17
 * @description:
 */
@Controller
public class FileController {

    private Logger logger = LoggerFactory.getLogger(FileController.class);

    @Autowired
    private FileStoreService fileStoreService;

    @Autowired
    private FileFolderService fileFolderService;

    @Autowired
    private MyFileService myFileService;

    @Value("${ftp.url}")
    private String ftpURL;

    @Value("${ftp.username}")
    private String ftpUsername;

    @Value("${ftp.password}")
    private String ftpPassword;

    @PostMapping("/uploadFile")
    @ResponseBody
    public Object uploadFile(HttpServletRequest request, @RequestParam("file") MultipartFile file) {
        Map<String, Integer> map = new HashMap<>();
        User user = (User) request.getSession().getAttribute("user");
        if (user.getLevel() == 1 || user.getLevel() == 3){
            map.put("code", 505);
            return map;
        }
        FileStore fileStore = fileStoreService.getStoreByUserId(user.getId());
        Integer folderId = Integer.valueOf(request.getHeader("folderId"));
        String filename = file.getOriginalFilename();
        List<MyFile> dbFiles = null;
        if (folderId == 0) {
            dbFiles = myFileService.getRootFilesByStoreId(fileStore.getId());
        } else {
            dbFiles = myFileService.getFilesByFolderId(folderId);
        }
        for (MyFile dbFile : dbFiles) {
            if ((dbFile.getName() + dbFile.getPostfix()).equals(filename)) {
                logger.error("当前文件已存在，上传失败！！！");
                map.put("code", 501);
                return map;
            }
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = format.format(System.currentTimeMillis());
        String path = user.getId() + "/" + dateStr + "/" + folderId;
        Integer sizeInt = Math.toIntExact(file.getSize() / 1024);
        if (fileStore.getCurrentSize() + sizeInt > fileStore.getMaxSize()) {
            logger.error("仓库已满，上传文件失败");
            map.put("code", 503);
            return map;
        }
        int dotIndex = filename.lastIndexOf(".");
        String postfix;
        int type;
        if (dotIndex > 1) {
            postfix = filename.substring(dotIndex).toLowerCase();
            filename = filename.substring(0, dotIndex);
            type = myFileService.getType(postfix);
        } else {
            postfix = "";
            type = myFileService.getType(postfix);
        }
        FtpUtil ftpUtil = FtpUtil.createFtpCli(ftpURL, ftpUsername, ftpPassword, "/");
        try {
            ftpUtil.uploadFile(filename + postfix, file.getInputStream(), path);
            MyFile newFile = new MyFile();
            newFile.setName(filename);
            newFile.setFolderId(folderId);
            newFile.setFilePath(path);
            newFile.setPostfix(postfix);
            newFile.setSize(sizeInt);
            newFile.setStoreId(fileStore.getId());
            newFile.setUploadTime(System.currentTimeMillis());
            newFile.setType(type);
            newFile.setDownloadCount(0);
            myFileService.addNewFile(newFile);
            fileStoreService.addStoreSize(fileStore, newFile.getSize());
            logger.info("文件上传成功！！！");
            map.put("code", 200);
        } catch (IOException e) {
            logger.error("文件上传服务器失败！！！");
            map.put("code", 504);
        }
        return map;
    }

    @RequestMapping("/deleteFile")
    public String deleteFile(HttpServletRequest request, @RequestParam Integer fId, Integer folderId) {
        User user = (User) request.getSession().getAttribute("user");
        if (user.getLevel() == 3) {
            return "redirect:/files?error=6&fId=" + folderId;
        }
        MyFile dbFile = myFileService.getFileById(fId);
        String ftpPath = dbFile.getFilePath() + "/" + dbFile.getName() + dbFile.getPostfix();
        FtpUtil ftpUtil = FtpUtil.createFtpCli(ftpURL, ftpUsername, ftpPassword, "/");
        try {
            ftpUtil.connect();
            ftpUtil.deleteFile(ftpPath);
            ftpUtil.disconnect();
            myFileService.deleteFile(dbFile.getId());
            fileStoreService.subStoreSize(dbFile.getStoreId(), dbFile.getSize());
            logger.info("文件删除成功！！！" + ftpPath);
        } catch (IOException e) {
            logger.error("文件删除失败！！！");
            return "redirect:/files?error=4&fId=" + folderId;
        }
        return "redirect:/files?fId=" + folderId;
    }

    @GetMapping("/downloadFile")
    public void downloadFile(HttpServletRequest request, HttpServletResponse response, @RequestParam Integer fId) throws IOException {
        User user = (User) request.getSession().getAttribute("user");
        MyFile dbFile = myFileService.getFileById(fId);
        if (user.getLevel() == 3 || user.getLevel() == 2) {
            response.sendRedirect("/files?error=6&fId=" + dbFile.getFolderId());
            return;
        }
        String ftpPath = dbFile.getFilePath() + "/" + dbFile.getName() + dbFile.getPostfix();
        FtpUtil ftpUtil = FtpUtil.createFtpCli(ftpURL, ftpUsername, ftpPassword, "/");
        try {
            OutputStream os = new BufferedOutputStream(response.getOutputStream());
            response.setCharacterEncoding("utf-8");
            response.setContentType("multipart/form-data");
            response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(dbFile.getName() + dbFile.getPostfix(), "UTF-8"));
            ftpUtil.connect();
            ftpUtil.downloadFileFromDailyDir(ftpPath, os);
            ftpUtil.disconnect();
            os.flush();
            os.close();
            dbFile.setDownloadCount(dbFile.getDownloadCount() + 1);
            myFileService.updateFile(dbFile);
            logger.info("文件下载成功！！！" + ftpPath);
        } catch (IOException e) {
            logger.error("文件下载失败！！！");
        }
    }

    @PostMapping("/updateFileName")
    public String updateFileName(HttpServletRequest request, MyFile file, Model model) {
        User user = (User) request.getSession().getAttribute("user");
        MyFile dbFile = myFileService.getFileById(file.getId());
        if (user.getLevel() == 3) {
            return "redirect:/files?error=6&fId=" + dbFile.getFolderId();
        }
        String oldName = dbFile.getName();
        String newName = file.getName();
        if (!oldName.equals(newName)) {
            FtpUtil ftpUtil = FtpUtil.createFtpCli(ftpURL, ftpUsername, ftpPassword, "/");
            String oldAllName = dbFile.getFilePath() + "/" + dbFile.getName() + dbFile.getPostfix();
            String newAllName = dbFile.getFilePath() + "/" + file.getName() + dbFile.getPostfix();
            Boolean reSuccess = ftpUtil.reName(oldAllName, newAllName);
            if (reSuccess) {
                dbFile.setName(newName);
                myFileService.updateFile(dbFile);
                logger.info("文件重命名成功！！！" + dbFile);
            }
        }
        return "redirect:/files?fid=" + dbFile.getFolderId();
    }

    @GetMapping("/getShareUrl")
    @ResponseBody
    public Map<String, Object> getShareUrl(HttpServletRequest request, HttpServletResponse response,
                                           @RequestParam Integer id, @RequestParam String url) throws IOException {
        User user = (User) request.getSession().getAttribute("user");
        if (user.getLevel() == 3) {
            response.sendRedirect("/files?error=6");
        }
        Map<String, Object> map = new HashMap<>();
        if (id != null) {
            MyFile dbFile = myFileService.getFileById(id);
            if (dbFile != null) {
                String path = request.getSession().getServletContext().getRealPath("/user_img/");
                url = url + "file/share?t=" + UUID.randomUUID().toString().substring(0, 10) + "&f=" + dbFile.getId() + "&p=" + dbFile.getUploadTime() + "" + dbFile.getSize();
                map.put("url", url);
            } else {
                logger.error("文件不存在！！！");
            }
        }
        return map;
    }

    @GetMapping("/file/share")
    public void shareFile(HttpServletResponse response, Integer f, String p, String t) {
        MyFile dbFile = myFileService.getFileById(f);
        if (dbFile == null) {
            return;
        }
        String pwd = dbFile.getUploadTime() + "" + dbFile.getSize();
        if (t == null || !pwd.equals(p)) {
            return;
        }
        String ftpPath = dbFile.getFilePath() + "/" + dbFile.getName() + dbFile.getPostfix();
        FtpUtil ftpUtil = FtpUtil.createFtpCli(ftpURL, ftpUsername, ftpPassword, "/");
        try {
            OutputStream os = new BufferedOutputStream(response.getOutputStream());
            response.setCharacterEncoding("utf-8");
            response.setContentType("multipart/form-data");
            response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(dbFile.getName() + dbFile.getPostfix(), "UTF-8"));
            ftpUtil.connect();
            ftpUtil.downloadFileFromDailyDir(ftpPath, os);
            ftpUtil.disconnect();
            os.flush();
            os.close();
            logger.info("文件下载成功！！！" + ftpPath);
        } catch (IOException e) {
            logger.error("文件下载失败！！！");
        }
    }
}
